﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using FurionApiDemo.Core.Entity;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using FurionApiDemo.Core.Implement.Menu.Dto;
using FurionApiDemo.Core.Manager.User;
using FurionApiDemo.Core.Service;
using FurionApiDemo.Core.Enum;
using System;
using Mapster;

namespace FurionApiDemo.Core.Implement.Menu
{
    public class MenuService : IMenuService, ITransient
    {
        private readonly IRepository<SysMenu> _sysMenuRep;  // 菜单表仓储  
        private readonly ICacheService _sysCacheService;
        private readonly IUserRoleService _sysUserRoleService;
        private readonly IRoleMenuService _sysRoleMenuService;
        private readonly IUserManager _userManager;
        public MenuService(IRepository<SysMenu> sysMenuRep,
            ICacheService sysCacheService,
            IRoleMenuService sysRoleMenuService,
            IUserRoleService sysUserRoleService,
            IUserManager userManager)
        {
            _sysMenuRep = sysMenuRep;
            _sysCacheService = sysCacheService;
            _sysRoleMenuService = sysRoleMenuService;
            _sysUserRoleService = sysUserRoleService;
            _userManager = userManager;
        }

        /// <summary>
        /// 获取登录人员的菜单权限
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<string>> GetLoginPermissionList()
        {
            var result = new List<string>();
            var permissions = await _sysCacheService.GetPermission(_userManager.UserId); // 先从缓存里面读取
            if (permissions == null || permissions.Count < 1)
            {
                if (!_userManager.SuperAdmin)
                {
                    var roleIdList = await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
                    var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
                    permissions = await _sysMenuRep.DetachedEntities.Where(u => menuIdList.Contains(u.Id))
                                                                    .Where(u => u.Status == (int)CommonStatus.ENABLE)
                                                                    .Where(t => t.Type == (int)MenuType.BTN)
                                                                    .Select(u => u.Permission).ToListAsync();
                }
                else
                {
                    permissions = await _sysMenuRep.DetachedEntities.Where(t => t.IsDeleted == false && t.Status == (int)CommonStatus.ENABLE)
                                                                    .Where(t => t.Type == (int)MenuType.BTN)
                                                .Select(t => t.Permission).ToListAsync();
                }
                await _sysCacheService.SetPermission(_userManager.UserId, permissions); // 缓存结果
            }
            return permissions;
        }

        /// <summary>
        /// 获取登录人员菜单
        /// </summary>
        /// <returns></returns>
        public async Task<List<MenuOutput>> GetLoginMenus()
        {
            var result = await _sysCacheService.GetMenu(_userManager.UserId, AppType.PC.ToString());


            if (result == null || result.Count < 1 || await _sysCacheService.GetAsync<bool>("IsChangeRoleMenu"))
            {
                if (_userManager.SuperAdmin)
                {
                    var menuList = await _sysMenuRep.AsQueryable()
                                 .Include(u => u.Childrens
                                    .Where(t => t.Status == (int)CommonStatus.ENABLE && t.IsDeleted == false)
                                    .OrderBy(t => t.Sort)
                                    )
                                 .Where(t => t.Pid == 0 && t.Status == (int)CommonStatus.ENABLE && t.IsDeleted == false)
                                 .OrderBy(t => t.Sort)
                                 .ToListAsync();
                    result = menuList.Adapt<List<MenuOutput>>();
                }
                else
                {
                    var roleIdList = await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
                    var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
                    var menuList = await _sysMenuRep.AsQueryable()
                                 .Include(u => u.Childrens
                                    .Where(t => t.Status == (int)CommonStatus.ENABLE && t.IsDeleted == false && menuIdList.Contains(t.Id))
                                    .OrderBy(t => t.Sort)
                                    )
                                 .Where(t => t.Pid == 0 && t.Status == (int)CommonStatus.ENABLE && t.IsDeleted == false && menuIdList.Contains(t.Id))
                                 .OrderBy(t => t.Sort)
                                 .ToListAsync();
                    result = menuList.Adapt<List<MenuOutput>>();
                }
                await _sysCacheService.SetMenu(_userManager.UserId, AppType.PC.ToString(), result);
                await _sysCacheService.SetAsync("IsChangeRoleMenu", false);
            }
            return result;
        }

        /// <summary>
        /// 获取菜单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<MenuOutput>> GetMenus(MenuInput input)
        {
            var result = await _sysCacheService.GetAsync<List<MenuOutput>>("MenuTree");
            if (result == null || result.Count < 1)
            {
                var menuList = await _sysMenuRep.AsQueryable()
                              .Include(u => u.Childrens
                                    .Where(t => t.Status == (input.Status.HasValue ? input.Status : t.Status)
                                        && t.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : t.IsDeleted))
                                    .OrderBy(t => t.Sort)
                                    )
                              .Where(t => t.Pid == 0
                                     && t.Status == (input.Status.HasValue ? input.Status : t.Status)
                                     && t.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : t.IsDeleted))
                              .OrderBy(t => t.Sort)
                              .ToListAsync();
                result = menuList.Adapt<List<MenuOutput>>();
                if (false)
                {
                    result = await _sysMenuRep.DetachedEntities.Where(t => t.Pid == 0 && t.Status == (input.Status.HasValue ? input.Status : t.Status)
                                                                    && t.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : t.IsDeleted)).Select(t =>
                                   new MenuOutput
                                   {
                                       Id = t.Id,
                                       Pid = t.Pid,
                                       Pids = t.Pids,
                                       Code = t.Code,
                                       Component = t.Component,
                                       Icon = t.Icon,
                                       Link = t.Link,
                                       Name = t.Name,
                                       Title = t.Title,
                                       IsTab = t.IsTab == 0 ? false : true,
                                       OpenType = t.OpenType,
                                       Permission = t.Permission,
                                       Redirect = t.Redirect,
                                       Remark = t.Remark,
                                       Router = t.Router,
                                       Sort = t.Sort,
                                       Status = t.Status,
                                       Type = t.Type,
                                       Visible = t.Visible,
                                       Weight = t.Weight,
                                       Childrens = _sysMenuRep.DetachedEntities.Where(p => p.Pid == t.Id && p.Status == (input.Status.HasValue ? input.Status : p.Status)
                                                                                && p.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : p.IsDeleted))
                                                                               .Select(p =>
                                                                                   new MenuOutput
                                                                                   {
                                                                                       Id = p.Id,
                                                                                       Pid = p.Pid,
                                                                                       Pids = p.Pids,
                                                                                       Code = p.Code,
                                                                                       Component = p.Component,
                                                                                       Icon = p.Icon,
                                                                                       Link = p.Link,
                                                                                       Name = p.Name,
                                                                                       Title = p.Title,
                                                                                       IsTab = p.IsTab == 0 ? false : true,
                                                                                       OpenType = p.OpenType,
                                                                                       Permission = p.Permission,
                                                                                       Redirect = p.Redirect,
                                                                                       Remark = p.Remark,
                                                                                       Router = p.Router,
                                                                                       Sort = p.Sort,
                                                                                       Status = p.Status,
                                                                                       Type = p.Type,
                                                                                       Visible = p.Visible,
                                                                                       Weight = p.Weight,
                                                                                       Childrens = _sysMenuRep.DetachedEntities.Where(l => l.Pid == p.Id &&
                                                                                                                                   l.Status == (input.Status.HasValue ? input.Status : l.Status)
                                                                                                                                   && l.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : l.IsDeleted))
                                                                                                                               .Select(l =>
                                                                                                                                   new MenuOutput
                                                                                                                                   {
                                                                                                                                       Id = l.Id,
                                                                                                                                       Pid = l.Pid,
                                                                                                                                       Pids = l.Pids,
                                                                                                                                       Code = l.Code,
                                                                                                                                       Component = l.Component,
                                                                                                                                       Icon = l.Icon,
                                                                                                                                       Link = l.Link,
                                                                                                                                       Name = l.Name,
                                                                                                                                       Title = l.Title,
                                                                                                                                       IsTab = l.IsTab == 0 ? false : true,
                                                                                                                                       OpenType = l.OpenType,
                                                                                                                                       Permission = l.Permission,
                                                                                                                                       Redirect = l.Redirect,
                                                                                                                                       Remark = l.Remark,
                                                                                                                                       Router = l.Router,
                                                                                                                                       Sort = l.Sort,
                                                                                                                                       Status = l.Status,
                                                                                                                                       Type = l.Type,
                                                                                                                                       Visible = l.Visible,
                                                                                                                                       Weight = l.Weight,
                                                                                                                                   }
                                                                                                                               ).OrderBy(l => l.Sort).ToList()
                                                                                   }
                                                                               ).OrderBy(p => p.Sort).ToList()
                                   }
                           ).OrderBy(t => t.Sort).ToListAsync();
                }
                await _sysCacheService.SetAsync("MenuTree", result);
            }
            return result;
        }

        /// <summary>
        /// 获取菜单列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<MenuOutput>> GetMenuList(MenuInput input)
        {
            var menuList = await _sysMenuRep.Where(t => t.Status == (input.Status.HasValue ? input.Status : t.Status)
                                       && t.IsDeleted == (input.IsDeleted.HasValue ? input.IsDeleted : t.IsDeleted))
                  .ToListAsync();
            return menuList.Adapt<List<MenuOutput>>();
        }

        /// <summary>
        /// 获取登录人员菜单列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<MenuOutput>> GetLoginMenuList()
        {
            var result = await _sysMenuRep.DetachedEntities
                .Where(t => t.Status == (int)CommonStatus.ENABLE &&
                        t.IsDeleted == false &&
                        (t.Type == (int)MenuType.MENU || t.Type == (int)MenuType.DIR))
                .Select(t =>
                        new MenuOutput
                        {
                            Id = t.Id,
                            Pid = t.Pid,
                            Code = t.Code,
                            Component = t.Component,
                            Icon = t.Icon,
                            Link = t.Link,
                            Name = t.Name,
                            Title = t.Title,
                            IsTab = t.IsTab == 0 ? false : true,
                            OpenType = t.OpenType,
                            Permission = t.Permission,
                            Redirect = t.Redirect,
                            Remark = t.Remark,
                            Router = t.Router,
                            Sort = t.Sort,
                            Status = t.Status,
                            Type = t.Type,
                            Visible = t.Visible,
                            Weight = t.Weight,
                        }
                        )
                .ToListAsync();
            return result;
        }

        /// <summary>
        /// 获取路由
        /// </summary>
        /// <returns></returns>
        public async Task<List<RouterOutput>> GetLoginRoutes()
        {
            var result = await _sysMenuRep.DetachedEntities
                .Where(t => t.Status == (int)CommonStatus.ENABLE &&
                        t.IsDeleted == false &&
                        (t.Type == (int)MenuType.MENU || t.Type == (int)MenuType.DIR))
                .Select(t =>
                        new RouterOutput
                        {
                            path = t.Router,
                            component = t.Component,
                            name = t.Name,
                            meta = new Dto.Meta
                            {
                                title = t.Title,
                                isTab = t.IsTab == 0 ? false : true
                            }
                        }
                        )
                .ToListAsync();
            return result;
        }

        /// <summary>
        /// 刷新菜单缓存
        /// </summary>
        /// <returns></returns>
        public async Task<bool> RefenceMenuCache()
        {
            await _sysCacheService.RefenceCache(_userManager.UserId, AppType.PC, CacheConType.Permission);
            return await _sysCacheService.RefenceCache(_userManager.UserId, AppType.PC, CacheConType.Menu);
        }

        /// <summary>
        /// 保存菜单（新增/更新）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<SaveMenuOutput> SaveMenu(SaveMenuInput input)
        {
            SysMenu menu = new SysMenu();
            if (input.Id.HasValue)
            {
                //更新
                menu = await _sysMenuRep.FirstOrDefaultAsync(t => t.Id == input.Id);
            }
            menu.Code = input.Code;
            menu.Component = input.Component;
            menu.Icon = input.Icon;
            menu.IsTab = input.IsTab;
            menu.Link = input.Link;
            menu.Name = input.Name;
            menu.OpenType = (int)input.OpenType;
            menu.Permission = input.Permission;
            if (input.Pid.HasValue)
            {
                menu.Pid = input.Pid.Value;
            }
            menu.Pids = input.Pids;
            menu.Redirect = input.Redirect;
            menu.Remark = input.Remark;
            menu.Router = input.Router;
            menu.Sort = input.Sort;
            menu.Status = (int)input.Status;
            menu.Title = input.Title;
            menu.Type = (int)input.Type;
            menu.Visible = input.Visible;
            menu.Weight = (int)input.Weight;
            menu.UpdatedTime = DateTime.Now;
            menu.UpdatedUserId = _userManager.UserId;
            if (input.Id.HasValue)
            {
                //更新
                await _sysMenuRep.UpdateAsync(menu);
            }
            else
            {
                //新增
                await _sysMenuRep.InsertAsync(menu);
            }
            await _sysCacheService.DelAsync("MenuTree");
            return menu.Adapt<SaveMenuOutput>();
        }

        /// <summary>
        /// 根据主键获取菜单信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<SaveMenuOutput> GetMenuById(long id)
        {
            SysMenu menu = await _sysMenuRep.FindAsync(id);
            return menu.Adapt<SaveMenuOutput>();
        }

        /// <summary>
        /// 删除菜单
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteMenu(long id)
        {
            SysMenu menu = await _sysMenuRep.AsQueryable().Include(t => t.Childrens).ThenInclude(t => t.Childrens).FirstOrDefaultAsync(t => t.Id == id);
            menu.Status = (int)CommonStatus.DELETED;
            menu.IsDeleted = true;
            await _sysMenuRep.UpdateAsync(menu);
            await _sysCacheService.DelAsync("MenuTree");
        }
    }
}
